/*
 * ANALIZADOR LÉXICO
 */

#include <stdio.h>
#include <stdlib.h>
#include "lex.h"

int getEvento(char c);
int yylex();
void grabarToken(int token);

int main(int argc, char *argv[])
{
	int tipoToken = 0;

	printf("Abriendo Archivo %s...", argv[1]);

	initEstados();

	/* Apertura de Archivo codigo fuente*/
	ArchFuente = fopen(argv[1], "r");

	/* Apertura de Archivo codigo fuente*/
	ArchSalida = fopen("salida.lex", "w");

	if (ArchFuente != NULL)
	{
		/*Confirmo que el archivo se abrio bien.*/
		printf("[OK]\n");

		CaracterLeido = CaracterAnterior = getc(ArchFuente);

		while (!feof(ArchFuente) && TipoToken != -1)
		{

			TipoToken = yylex();

			grabarToken(TipoToken);

			CaracterAnterior = CaracterLeido;

			CaracterLeido = (char) getc(ArchFuente);

		}

	}
	else
	{
		printf("[MAL]\n");
		printf("Error de apertura de archivo.\n");
	}

	if (TipoToken == -1)
	{
		printf("***************Error Léxico***************\n");
	}

    GrabarTS();

	/* Cierre de Archivos */

	printf("Cerrando archivo entrada...");
	fclose(ArchFuente);
	printf("[OK]\n");

	printf("Cerrando archivo salida...");
	fclose(ArchSalida);
	printf("[OK]\n");

	return 0;
}

int yylex()
{
	int estado = ESTADO_INICIAL;
	int estadoFinal = CANT_ESTADOS;
	int columna = 0;

	while (estado != estadoFinal)
	{

		/*Obtengo la columna de la matriz*/
		columna = getEvento(CaracterLeido);

		if (columna >= 0)
		{
			/*Ejecuto la función correspondiente*/
			(*Procesos[estado][columna])();

			estado = NuevoEstado[estado][columna];

			if ( estado != estadoFinal ){
				CaracterAnterior = CaracterLeido;
				CaracterLeido = (char) getc(ArchFuente);
			}



		}
		else
		{
			TipoToken = -1;
			estado = estadoFinal;
		}

	}


	if ( CaracterLeido != '\n' )
		ungetc(CaracterLeido, ArchFuente);

	/*TODO: TABLA DE SIMBOLOS Guardo el valor en yylval*/

	yylval = 1;

	return TipoToken;

}

int getEvento(char c)
{
	int ret = -1;

	/* Verifico si 'c' esta en el rango [A-Za-z] y devuelvo la columna 0 */
	if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))
	{
		ret = 0;

		/* Verifico si 'c' esta en el rango [0-9] y devuelvo la columna 1 */
	}
	else if (c >= '0' && c <= '9')
	{

		ret = 1;

	}
	else
	{

		switch (c)
		{
		/**/
		case '.':
			ret = 2;
			break;
		case '@':
			ret = 3;
			break;
		case '=':
			ret = 4;
			break;
		case '<':
			ret = 5;
			break;
		case '>':
			ret = 6;
			break;
		case '+':
			ret = 7;
			break;
		case '-':
			ret = 8;
			break;
		case '*':
			ret = 9;
			break;
		case '/':
			ret = 10;
			break;
		case '(':
			ret = 11;
			break;
		case ')':
			ret = 12;
			break;
		case '\"':
			ret = 13;
			break;
		case '!':
			ret = 14;
			break;
		case '&':
			ret = 15;
			break;
		case '|':
			ret = 16;
			break;
		case ',':
			ret = 17;
			break;
		case ':':
			ret = 18;
			break;
		case '[':
			ret = 19;
			break;
		case ']':
			ret = 20;
			break;
		case ';':
			ret = 21;
			break;
		case '\n':
			ret = 22;
			break;
		case ' ':
			ret = 22;
			break;
		case '\t':
			ret = 22;
			break;
		case '\0':
			ret = 22;
			break;
		default:
			printf("Caracter no reconocido: '%c'\n", c);

		}

	}

	return ret;
}

void grabarToken(int token)
{
	switch (token)
	{
	case ID:
		fprintf(ArchSalida, "<ID:%s>\n", Contenido);
		break;
	case CTE_NUM:
		fprintf(ArchSalida, "<ENTERO:%s>\n", Contenido);
		break;
	case CTE_REAL:
		fprintf(ArchSalida, "<FLOTANTE:%s>\n", Contenido);
		break;
	case CTE_STRING:
		fprintf(ArchSalida, "<STRING:%s>\n", Contenido);
		break;
	case PALABRA_RESERVADA:
		fprintf(ArchSalida, "<PAL_RESERVADA:%s>\n", Contenido);
		break;
	case COMA:
		fprintf(ArchSalida, "<COMA>\n", token);
		break;
	case DOS_PUNTOS:
		fprintf(ArchSalida, "<DOS_PUNTOS>\n", token);
		break;
	case FIN_DE_LINEA:
		fprintf(ArchSalida, "<FIN_DE_LINEA>\n", token);
		break;
	case OP_COMP:
		fprintf(ArchSalida, "<OP_COMP>\n", token);
		break;
	case OP_ASIG:
		fprintf(ArchSalida, "<OP_ASIG>\n", token);
		break;
	case OP_MENOR_IG:
		fprintf(ArchSalida, "<OP_MENOR_IG>\n", token);
		break;
	case OP_MENOR:
		fprintf(ArchSalida, "<OP_MENOR>\n", token);
		break;
	case OP_MAYOR_IG:
		fprintf(ArchSalida, "<OP_MAYOR_IG>\n", token);
		break;
	case OP_MAYOR:
		fprintf(ArchSalida, "<OP_MAYOR>\n", token);
		break;
	case OP_SUMA:
		fprintf(ArchSalida, "<OP_SUMA>\n", token);
		break;
	case OP_RESTA:
		fprintf(ArchSalida, "<OP_RESTA>\n", token);
		break;
	case OP_MULT:
		fprintf(ArchSalida, "<OP_MULT>\n", token);
		break;
	case OP_DIV:
		fprintf(ArchSalida, "<OP_DIV>\n", token);
		break;
	case OP_AND:
		fprintf(ArchSalida, "<OP_AND>\n", token);
		break;
	case OP_OR:
		fprintf(ArchSalida, "<OP_OR>\n", token);
		break;
	case OP_DIST:
		fprintf(ArchSalida, "<OP_DIST>\n", token);
		break;
	case OP_NEG:
		fprintf(ArchSalida, "<OP_NEG>\n", token);
		break;
	case PAR_ABRE:
		fprintf(ArchSalida, "<PAR_ABRE>\n", token);
		break;
	case PAR_CIERRA:
		fprintf(ArchSalida, "<PAR_CIERRA>\n", token);
		break;
	case CORCH_ABRE:
		fprintf(ArchSalida, "<CORCH_ABRE>\n", token);
		break;
	case CORCH_CIERRA:
		fprintf(ArchSalida, "<CORCH_CIERRA>\n", token);
		break;

	}

}
